﻿

using AutoMapper;
using Cari.IBP.Platform.Sidecar;
using Cari.IBP.Platform.Sidecar.Extensions;
using Cari.IBP.Platform.Utility;

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.WebEncoders;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
using Pomelo.EntityFrameworkCore.MySql.Storage;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
using Cari.IBP.Platform.Sidecar;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Ccteg.Common;
using Ccteg.DB;

namespace Cctegaq.Api
{
    public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment appEnv)
        {
            Configuration = configuration;
            CurrentEnvironment = appEnv;
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        }
        private IWebHostEnvironment CurrentEnvironment { get; set; }
        public IConfiguration Configuration { get; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {

            //开启跨域 https://www.cnblogs.com/linyijia/p/12981830.html
            services.AddCors(o =>
                o.AddPolicy("CorsPolicy",
                    builder => builder
                      //.WithOrigins("http://localhost:9000", "http://101.37.168.17:9000", "http://106.14.198.193", "http://*", "https://*")
                      .AllowAnyHeader().AllowAnyMethod().AllowCredentials().SetIsOriginAllowed(p => true)
                ));

            //添加目录浏览
            services.AddDirectoryBrowser();

            //开启缓存
            services.AddMemoryCache();
            //开启上下文 包括读取配置文件
            services.AddHttpContextAccessor();
            //单列注入
            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
            //获取节点 appsettings  t 映射到实体上
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppAuthenticationSettings>(appSettingsSection);
            services.AddSingleton(services.Configure<AppAuthenticationSettings>(appSettingsSection));
            //************************获取节点 ConsulServiceSettings 下Secret 映射到实体上

            //生产环境
            var appConsulSettingsSection = Configuration.GetSection("ConsulServiceSettings");
            //测试环境
            if (CurrentEnvironment.IsDevelopment())
            {
                appConsulSettingsSection = Configuration.GetSection("ConsulServiceSettings_Test");
            }
            var consulServiceSettings = appConsulSettingsSection.Get<ConsulServiceSettings>();

            services.Configure<ConsulServiceSettings>(appConsulSettingsSection);
            services.AddSingleton(appConsulSettingsSection.Get<ConsulServiceSettings>());
            //添加httpClient
            services.AddHttpClient();

            //https://www.cnblogs.com/taotaozhuanyong/p/11594931.html
            //采用系统cookie 类型验证 和登录时候给定的  (SignInAsync) Scheme
            //services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            //.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            //   {

            //       options.LoginPath = "/api/Login/Index";
            //       options.AccessDeniedPath = "/api/Login/Denied";
            //   });
            /*** my***/
            // JWT token
            // var appSettings = appSettingsSection.Get<AppAuthenticationSettings>();
            //注册JWT Bearer认证服务
            // services.AddJwtBearerAuthentication(appSettings);
            /*** end-my***/



            services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
            //添加AutoMapper
            services.AddAutoMapper(typeof(Startup));
            //中文解析
            services.Configure<WebEncoderOptions>(options =>
                options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs)
            );

            //https://www.cnblogs.com/zmaiwxl/p/9229143.html 可以看这个文档NewtonsoftJson 配置
            //使用NewtonsoftJson
            services.AddControllers().AddNewtonsoftJson(options =>
            {
                //忽略循环引用
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                //不更改元数据的key的大小写
                //options.SerializerSettings.ContractResolver = new DefaultContractResolver();

            });


            #region
            var applicationData = new ApplicationData(Configuration);

#if DEBUG
            //生成资源描述文件
            ResourceFileGenerator.GenerateResourcesFile(Assembly.GetExecutingAssembly(), applicationData);
#endif

            services.AddSingleton(applicationData);

           
            services.AddDbContextPool<MySqlDbContext>(options => options
              .UseMySql(applicationData.GetMySql(), mySqlOptions => mySqlOptions
                  .ServerVersion(new ServerVersion(new System.Version(8, 0, 19), ServerType.MySql))
              ).UseLolita());

            ////注入MySQL
            //services.AddDbContextPool<MySqlDbContext>(options =>
            //{
            //    options.UseMySql(Configuration.GetConnectionString("MySqlDefaultConnection"));

            //    options.UseMySqlLolita();
            //});

            //配置平台jwt认证
            services.AddIbpJwtAuthentication(applicationData);

            //配置平台授权
            services.AddIbpAuthorization(op =>
            {
                op.UseRedis(applicationData.GetRedis(2));
            });

            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });
            #endregion
            ////注入sqlserver
            //services.AddDbContext<SqlServerDbContext>(options =>
            //    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
            //    // 如果使用SQL Server 2008数据库，请添加UseRowNumberForPaging的选项
            //    // 参考资料:https://github.com/aspnet/EntityFrameworkCore/issues/4616 
            //    // 【重要说明】:2020-03-23更新，微软官方最新的Entity Framework Core已不再支持UseRowNumberForPaging()，请尽量使用SQL Server 2012 +版本
            //    //options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),b=>b.UseRowNumberForPaging())
            //    );



            ////注入MySQL
            //services.AddDbContextPool<MySqlDbContext>(options =>
            //{
            //    options.UseMySql(Configuration.GetConnectionString("MySqlDefaultConnection"));

            //    options.UseMySqlLolita();
            //});
            //开启swagger   在线api文档
            services.AddSwaggerGen(c =>
            {

                //按模块 需要在控制器上加    [ApiExplorerSettings(GroupName = "jcsj")] 属于哪个组
                c.SwaggerDoc("aqgl", new OpenApiInfo { Title = "安全管理模块Api", Version = "v1" });
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "系统模块Api", Version = "v1" });

                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);

                
                var xmlPathCommon = Path.Combine(AppContext.BaseDirectory, "Ccteg.Common.xml");
                c.IncludeXmlComments(xmlPathCommon, true);
               
                 c.IncludeXmlComments(xmlPath, true);

               


                //设置要展示的接口
                c.DocInclusionPredicate((docName, apiDes) =>
                 {
                     if (!apiDes.TryGetMethodInfo(out MethodInfo method))
                         return false;
                     /*使用ApiExplorerSettingsAttribute里面的GroupName进行特性标识
                         * DeclaringType只能获取controller上的特性
                       * 我们这里是想以action的特性为主
                       * */
                     var version = method.DeclaringType.GetCustomAttributes(true).OfType<ApiExplorerSettingsAttribute>().Select(m => m.GroupName);
                     if (docName == "aqgl" && !version.Any())
                         return true;
                     //这里获取action的特性
                     var actionVersion = method.GetCustomAttributes(true).OfType<ApiExplorerSettingsAttribute>().Select(m => m.GroupName);
                     if (actionVersion.Any())
                         return actionVersion.Any(v => v == docName);
                     return version.Any(v => v == docName);
                 });
            });
            //禁用默认ModelState行为
            services.Configure<ApiBehaviorOptions>(options =>
            {
                options.SuppressModelStateInvalidFilter = true;
            });
            // 注入日志 Log4Net
            services.AddLogging(config =>
            {
                config.AddLog4Net();
            });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, Microsoft.AspNetCore.Hosting.IApplicationLifetime lifetime)
        {


            app.UseDeveloperExceptionPage();
            //app.UseExceptionHandler("/error/500");
            //app.UseStatusCodePagesWithReExecute("/error/{0}");
            /*
                静态文件权限（app.UseStaticFiles()）
                默认文件设置（app.UseDefaultFiles();）
                是否开放目录访问（app.UseDirectoryBrowser）
            */
            //开启静态文件
            app.UseStaticFiles(); // For the wwwroot folder
            //开启外部文件 
            //app.UseStaticFiles(new StaticFileOptions()
            //{
            //    FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @"Upload")),
            //    RequestPath = new PathString("/Upload"),
            //});

            //app.UseDirectoryBrowser(); EnableDirectoryBrowsing = false //启用浏览 services.AddDirectoryBrowser();
            //app.UseFileServer

            app.UseAuthentication();
            app.UseCors("CorsPolicy");
            //自定义中间件 异常处理
            app.ConfigureCustomExceptionMiddleware();

            //获取所有注入的服务
            var serviceProvider = app.ApplicationServices;
            var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
            //权限验证 重要 采用的System.Security.Principal  Identity   -- ClaimsPrincipal   有点老吧  其实也是一个cookie   采用自定义策略  搭配jwt
            AuthContextService.Configure(httpContextAccessor);

            app.UseRouting();
            app.UseCookiePolicy();

            app.UseAuthorization();
            //增加平台授权中间件
            app.UseIbpAuthorization();
            //增加平台操作日志中间件
            // app.UseIbpOperationLog();

            if (!env.IsDevelopment())
            {
                app.UseSpaStaticFiles();
            }
            app.UseEndpoints(ep =>
            {
                ep.MapControllerRoute(name: "areaRoute", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
                ep.MapControllerRoute(name: "apiDefault", pattern: "api/{controller=Home}/{action=Index}/{id?}");
                ep.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
            });
            //初始化系统  处理二级单位数据
            // KafDataservice.ReportingInitialize(app.ApplicationServices.GetService<IServiceProvider>());

            app.UseSwagger(o => { });

            //启用SwaggerUI样式
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/aqgl/swagger.json", "安全管理模块");
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "系统模块");
                // c.SwaggerEndpoint("/swagger/aqfx/swagger.json", "安全风险模块");
                //默认展开
                c.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None);
                //c.RoutePrefix = "";
            });

            //注册consul
            app.RegisterConsul(lifetime, app.ApplicationServices.GetService<ConsulServiceSettings>());


            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });



        }
    }
}
